﻿using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;

namespace ComicReader.Controls
{
    [ContentProperty("Content")]
    [TemplatePart(Name = Const.ScrollViewerName, Type = typeof(ScrollViewer))]
    [TemplatePart(Name = Const.ViewBoxName, Type = typeof(Viewbox))]
    [TemplatePart(Name = Const.ZoomSliderPanelName, Type = typeof(StackPanel))]
    [TemplatePart(Name = Const.ZoomSliderName, Type = typeof(Slider))]
    public class ZoomPanner : ContentControl
    {
        private static class Const
        {
            public const string ScrollViewerName = "PART_ScrollViewer";
            public const string ViewBoxName = "PART_ViewBox";

            public const string ZoomSliderPanelName = "PART_ZoomSliderPanel";
            public const string ZoomSliderName = "PART_ZoomSlider";

        }

        private ScrollViewer TemplatedScrollViewer;
        private Viewbox TemplatedViewbox;

        private Slider TemplatedZoomSlider;

        private Size OriginalSize;

        Point ScrollStartPoint = default(Point);
        Point ScrollStartOffset = default(Point);

        public ZoomPanner()
        {
            DefaultStyleKey = typeof(ZoomPanner);
        }


        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            TemplatedScrollViewer = GetTemplateChild(Const.ScrollViewerName) as ScrollViewer;
            if (TemplatedScrollViewer == null) return;

            TemplatedViewbox = GetTemplateChild(Const.ViewBoxName) as Viewbox;
            if (TemplatedViewbox == null) return;

            TemplatedViewbox.Loaded += (TemplatedViewboxLoaded);


            var panel = Content as FrameworkElement;
            if (panel == null) return;
            panel.MouseLeftButtonDown += (TemplatedOuterCanvasMouseLeftButtonDown);
            panel.MouseLeftButtonUp += (TemplatedOuterCanvasMouseLeftButtonUp);
            panel.MouseMove += (TemplatedOuterCanvasMouseMove);
            panel.DataContextChanged += new DependencyPropertyChangedEventHandler(panel_DataContextChanged);

            TemplatedZoomSlider = GetTemplateChild(Const.ZoomSliderName) as Slider;
            if (TemplatedZoomSlider == null) return;
            TemplatedZoomSlider.ValueChanged += (TemplatedZoomSliderValueChanged);

        }

        void panel_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            OriginalSize = ((FrameworkElement) Content).DesiredSize;
        }


        void TemplatedViewboxLoaded(object sender, RoutedEventArgs e)
        {
            OriginalSize = TemplatedViewbox.DesiredSize;
        }

        void TemplatedZoomSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var zoomSlider = sender as Slider;

            var value = e.NewValue;
            if (zoomSlider == null) return;

            if (value < zoomSlider.Minimum || value > zoomSlider.Maximum) return;

            TemplatedViewbox.Width = OriginalSize.Width * value;
            TemplatedViewbox.Height = OriginalSize.Height * value;
        }

        void TemplatedOuterCanvasMouseMove(object sender, MouseEventArgs e)
        {
            // Get the new scroll position.
            var point = e.GetPosition(this);

            if (ScrollStartPoint == default(Point)) return;

            // Determine the new amount to scroll.
            var delta = new Point(
                (point.X > ScrollStartPoint.X) ? -(point.X - ScrollStartPoint.X) : (ScrollStartPoint.X - point.X),
                (point.Y > ScrollStartPoint.Y) ? -(point.Y - ScrollStartPoint.Y) : (ScrollStartPoint.Y - point.Y));

            // Scroll to the new position.
            TemplatedScrollViewer.ScrollToHorizontalOffset(ScrollStartOffset.X + delta.X);
            TemplatedScrollViewer.ScrollToVerticalOffset(ScrollStartOffset.Y + delta.Y);
        }

        void TemplatedOuterCanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ScrollStartPoint = default(Point);
        }

        void TemplatedOuterCanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ScrollStartOffset.X = TemplatedScrollViewer.HorizontalOffset;
            ScrollStartOffset.Y = TemplatedScrollViewer.VerticalOffset;
            ScrollStartPoint = e.GetPosition(null);
        }
    }
}